package raytracing;

import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

import model.Scene;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

import raytracing.gui.GuiFrame;
import raytracing.gui.ShowJFrame;
import scparser.Parser;
import scparser.ParserHelper;
import scparser.factory.primitiveFactory.FactoryException;

public class RayTraceMain extends JFrame {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private static Options options;
	private static Option i;
	private static Option o;
	private static Option time;

	private static Option progress;
	private static Option inefficientColission;
	private static Option multithreading;
	private static Option softshadows;

	private static Option gui;
	private static Option show;
	private static Option dof;

	private static final String EXTENSION = ".sc";

	public static void main(String[] args) {
		CommandLineParser parser = new GnuParser();
		init();
		HelpFormatter formatter = new HelpFormatter();

		try {
			// parse the command line arguments
			CommandLine line = parser.parse(options, args);

			if (line.hasOption("gui")) {
				GuiFrame g = new GuiFrame();
				g.setVisible(true);
			} else {
				String inputFileName = line.getOptionValue("i");
				String outputFileName;
				String imageExtension = null;
				int fov = 60;

				long time = System.currentTimeMillis();

				if (!EXTENSION.equals(inputFileName.substring(inputFileName
						.length() - 3))) {
					System.out
							.println("error input file type, it is must be .sc file");
					System.exit(-1);
				}

				if (line.hasOption("fov")) {
					fov = Integer.parseInt(line.getOptionValue("fov"));
					ParserHelper.fov = fov;
				}

				if (line.hasOption("o")) {
					outputFileName = line.getOptionValue("o");
					imageExtension = outputFileName.substring(outputFileName
							.length() - 3);
				} else {
					imageExtension = "png";
					outputFileName = inputFileName.substring(0,
							inputFileName.length() - 3)
							+ "." + imageExtension;
				}

				if (!imageExtension.equals("png")
						&& !imageExtension.equals("bmp")) {
					System.out.println("image file type unsupported");
					System.exit(-1);
				}
				Scene scene = null;
				scene = Parser.instance().parse(inputFileName);

				RayTracer rayTracer = new RayTracer(scene, scene.image.width,
						scene.image.height, new TraceDepth(1, 1, 4));

				// parametros para el debugging
				if (line.hasOption("progress")) {
					rayTracer.PROGRESS_ENABLED = true;
				}
				if (line.hasOption("inefficientColission")) {
					rayTracer.OCTTREE_ENABLED = false;
				}
				if (line.hasOption("softshadows")) {
					rayTracer.SOFT_SHADOW_ENABLED = true;
				}
				if (line.hasOption("multithreading")) {
					rayTracer.MULTITHREAD_ENABLED = true;
				}
				if (line.hasOption("dof")) {
					rayTracer.DOF = Double.parseDouble(line
							.getOptionValue("dof"));
				}

				BufferedImage bufferedImage = null;
				bufferedImage = rayTracer.Render();

				if (imageExtension.equals("png")) {
					RayTracer.savePNG(bufferedImage, outputFileName);
				} else {
					RayTracer.saveBMP(bufferedImage, outputFileName);
				}
				System.out.println("Raytrace done!");
				if (line.hasOption("t")) {
					System.out.println("time elapsed: "
							+ (System.currentTimeMillis() - time) + " ms.");
				}
				if (line.hasOption("show")) {
					// create a windows
					new ShowJFrame(rayTracer);
				}

			}

		} catch (FactoryException e) {
			System.out.println("Parse error: " + e.getMessage());
			System.exit(-1);
		} catch (ParseException e) {
			formatter.printHelp("RayTracing", options);
			System.out.println(e.getMessage());
			System.exit(-1);
		} catch (Exception e) {
			System.out.println("Raytrace error...");
			e.printStackTrace();

			System.exit(-1);
		}

	}

	@SuppressWarnings("static-access")
	public static void init() {
		options = new Options();
		time = new Option("t", false, "show elapsed time");
		i = OptionBuilder.withArgName("input file").hasArg()
				.withDescription("scene file name").create("i");
		i.setRequired(true);
		o = OptionBuilder.withArgName("output file").hasArg()
				.withDescription("ouput file name").create("o");
		progress = OptionBuilder.withDescription("Show progress").create(
				"progress");
		inefficientColission = OptionBuilder.withDescription(
				"Uses inefficientColission instead octtree (just for debug)")
				.create("inefficientColission");
		multithreading = OptionBuilder.withDescription(
				"Uses multithreading (just for debug)")
				.create("multithreading");
		softshadows = OptionBuilder.withDescription(
				"Uses softshadows (just for debug)").create("softshadows");

		gui = new Option("gui", false, "gui interface");
		show = new Option("show", false, "show the rendered image");
		dof = new Option("dof", true, "depth of the field");

		options.addOption(i);
		options.addOption(o);
		options.addOption(time);
		options.addOption(progress);

		options.addOption(multithreading);
		options.addOption(softshadows);
		options.addOption(show);
		options.addOption(gui);
		options.addOption(dof);
		options.addOption(inefficientColission);
	}

	public class ImagePanel extends JPanel {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private BufferedImage image;

		public ImagePanel(BufferedImage image) {
			this.image = image;
		}

		public void paintComponent(Graphics g) {
			g.drawImage(image, 0, 0, null); // see javadoc for more info on the
											// parameters

		}

	}

}
